﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using ControlConditionList = System.Collections.Generic.Dictionary<
	System.Windows.Forms.Control, System.Collections.Generic.List<
		System.Collections.Generic.KeyValuePair<
			System.Func<bool>, System.String>>>;



namespace BReusable
{

	public class ErrorProviderManager
	{
		private readonly ErrorProvider _ep;

		readonly ControlConditionList _dic =
			new ControlConditionList();

		readonly Dictionary<Control, List<String>> _dicPossibleErrorStrings = new Dictionary<Control, List<String>>();
		readonly List<Control> _verifyWithErrorProviderList = new List<Control>();

		readonly Dictionary<Control, System.ComponentModel.CancelEventHandler> _autoValidatingControls =
			new Dictionary<Control, System.ComponentModel.CancelEventHandler>();

		public ErrorProviderManager(Form form)
		{
			_ep = new ErrorProvider(form);
		}

		public bool HasErrors()
		{
			var result = false;
			foreach (var item in _dic.Keys)
			{

				var itemHasErrors = HasErrors(item);
				if (itemHasErrors) result = true;
			}
			foreach (var item in _verifyWithErrorProviderList)
			{
				if (_ep.GetError(item).IsNullOrEmpty() == false)
					result = true;
			}
			return result;
		}

		public bool HasErrors(Control item)
		{


			var itemHasErrors = false;
			if (_ep.GetError(item).IsNullOrEmpty() == false &&
					_dicPossibleErrorStrings[item].Contains(_ep.GetError(item)) == false)
				itemHasErrors = true;
			else
			{
				foreach (var kvp in _dic[item])
				{
					if (kvp.Key.Invoke())
					{
						_ep.SetError(item, kvp.Value);
						itemHasErrors = true;
						break;
					}

				}

				if (itemHasErrors == false)
					_ep.SetError(item, string.Empty);
			}
			return itemHasErrors;
		}

		public Control GetFirstError()
		{
			foreach (var item in _dic.Keys)
			{
				var itemHasErrors = HasErrors(item);
				if (itemHasErrors) return item;
			}
			foreach (var item in _verifyWithErrorProviderList)
			{
				if (_ep.GetError(item).IsNullOrEmpty() == false)
					return item;
			}
			return null;
		}
		public void AddErrorCondition(Control c, Func<bool> errorCondition, String errorMessage)
		{
			if (errorMessage.IsNullOrWhitespace() == false)
			{
				if (_verifyWithErrorProviderList.Contains(c))
					_verifyWithErrorProviderList.Remove(c);
				if (_dic.ContainsKey(c) == false)
					_dic.Add(c, new List<KeyValuePair<Func<bool>, string>>());
				_dic[c].Add(new KeyValuePair<Func<bool>, String>(errorCondition, errorMessage));
				if (_dicPossibleErrorStrings.ContainsKey(c) == false)
					_dicPossibleErrorStrings.Add(c, new List<string>());
				_dicPossibleErrorStrings[c].Add(errorMessage);
			}
		}

		/// <summary>
		/// Automatically refreshes errorProvider based on errorConditions
		/// </summary>
		/// <param name="c"></param>
		/// <param name="errorCondition"></param>
		/// <param name="errorMessage"></param>
		public void AddErrorWithValidatingCheck(Control c, Func<bool> errorCondition, String errorMessage)
		{
			AddErrorCondition(c, errorCondition, errorMessage);
			if (_autoValidatingControls.ContainsKey(c) == false)
			{_autoValidatingControls.Add(c,(sender, e) => HasErrors(c));
				c.Validating +=_autoValidatingControls[c] ;
			}
			HasErrors(c);
		}

		//public void AddWarningWithValidatingCheck(Control c, Func<bool> errorCondition, string errorMessage)
		//{
		//    _ep.
		//}
		public void SetCustomError(Control c, string errorMessage)
		{
			if (_dicPossibleErrorStrings.ContainsKey(c) == false && _verifyWithErrorProviderList.Contains(c) == false)
				_verifyWithErrorProviderList.Add(c);
			_ep.SetError(c, errorMessage);
		}

		public void RemoveCustomError(Control c)
		{
			_ClearError(c);
			if(_verifyWithErrorProviderList.Contains(c))
				_verifyWithErrorProviderList.Remove(c);
			HasErrors(c);

		}

		private void _ClearError(Control c)
		{
			_ep.SetError(c, string.Empty);
		}

		public void RefreshErrors()
		{
			HasErrors();
		}

	}

}
